#include "GameEngine.h"

//Constructeur
GameEngine::GameEngine()
{
    numCurrentMove = 0;
    board = new Board();
    playerTable[p1] = new Player(p1, tr("Player 1"), Local, Black);
    playerTable[p2] = new Player(p2, tr("Player 2"), Local, White);
    clearMovesList();
    regularMovesListTemp.clear();
    currentPlayer = p1;
    isFinished = false;
    movesSavedList.clear();

    //Initialise les coups réguliers ds regularMovesList pour la sauvegarde du premier coup...
	regularMovesListTemp.push_back( Move(2,3,Black) );
	regularMovesListTemp.push_back( Move(3,2,Black) );
	regularMovesListTemp.push_back( Move(4,5,Black) );
	regularMovesListTemp.push_back( Move(5,4,Black) );
	regularMovesListTemp.push_back( Move(5,3,White) );
	regularMovesListTemp.push_back( Move(4,2,White) );
	regularMovesListTemp.push_back( Move(2,4,White) );
	regularMovesListTemp.push_back( Move(3,5,White) );

	redoAllowed = false;
	undoAllowed = false;
 
// cout << "regularMovesListTemp.size() = " << regularMovesListTemp.size() << endl;   

}



//Destruteur
GameEngine::~GameEngine()
{
	delete board;
	delete playerTable[p1];
	delete playerTable[p2];
}



//Lance la partie
void GameEngine::startGame()
{
	askMove();
}



//Accesseur de la variable 'board'
Board* GameEngine::getBoard()
{
	return board;
}



//Accesseur de la variable 'player'
Player* GameEngine::getPlayer( int id )
{
	return playerTable[id];
}


Player** GameEngine::getPlayer()
{
	return playerTable;
}



//Accesseur de la variable 'movesList'
vector<Move> GameEngine::getMovesList()
{
	return movesList;
}


		
//Accesseur de la variable 'regularMovesListTemp'
vector<Move> GameEngine::getRegularMovesListTemp()
{
	return regularMovesListTemp;
}



//Accesseur de la variable 'currentPlayer'
int GameEngine::getCurrentPlayer()
{
	return currentPlayer;
}



//Initialisation de l'affichage
void GameEngine::initializationDisplay()
{
	playerInitializationDisplay();
	updatingMovesListDisplay();
}



/* Initialisation des variables de la partie
**
** Initialise les données pour débuter une nouvelle partie
*/
void GameEngine::initialization()
{
    board->initialization();
    playerTable[p1]->initialization();
    playerTable[p2]->initialization();
	clearMovesList();
    regularMovesListTemp.clear();
    currentPlayer = p1;
    isFinished = false;
	numCurrentMove = 0;
    movesSavedList.clear();
    
//Initialise les coups réguliers ds regularMovesList pour la sauvegarde du premier coup...
	regularMovesListTemp.push_back( Move(2,3,Black) );
	regularMovesListTemp.push_back( Move(3,2,Black) );
	regularMovesListTemp.push_back( Move(4,5,Black) );
	regularMovesListTemp.push_back( Move(5,4,Black) );
	regularMovesListTemp.push_back( Move(5,3,White) );
	regularMovesListTemp.push_back( Move(4,2,White) );
	regularMovesListTemp.push_back( Move(2,4,White) );
	regularMovesListTemp.push_back( Move(3,5,White) );

	redoAllowed = false;
	undoAllowed = false;

//MAJ Affichage
	updatingScoreDisplay();
	updatingNumMovesDisplay();
 
//Redémarage partie automatique
	askMove();    
}



//Récupération du coup à jouer
void GameEngine::recupMove(int x,int y)
{	
//	cout << "Entre ds GameEngine::recupMove()" << endl;
	emit enableUndoMoveAction(false);
	emit enableRedoMoveAction(false);
	playMove( Move(x,y) );
}



//Lance le tour de jeu suivant, si la partie n'est pas terminée
void GameEngine::nextTurn()
{
	if( getIsFinished() )
	{
		whoWins();
	}
	else
	{
		askMove();
	}
}	



//Modifie les noms et types des joueurs
/*void GameEngine::updatePlayers(QString name_p1, TypePlayer type_p1, QString name_p2, TypePlayer type_p2)
{
	bool ret = false;
	if( playerTable[p1]->getName() != name_p1)
	{
		playerTable[p1]->setName(name_p1);
		ret = true;
	}
	if( playerTable[p2]->getName() != name_p2)
	{
		playerTable[p2]->setName(name_p2);
		ret = true;
	}
	if( playerTable[p1]->getType() != type_p1 )
	{
		playerTable[p1]->setType(type_p1);
		ret = true;
	}
	if( playerTable[p2]->getType() != type_p2 )
	{
		playerTable[p2]->setType(type_p2);
		ret = true;
	}
	playerInitializationDisplay();
//	return ret;
}
*/



//Mutateur de la variable 'isFinished'
void GameEngine::setIsFinished(bool b)
{
    isFinished = b;
}



//Accesseur de la variable 'isFinished'
bool GameEngine::getIsFinished()
{
    return isFinished;
}



/* Joueur suivant
**
** Modifie le joueur courant
*/
void GameEngine::nextPlayer()
{
    if( currentPlayer == p1 )
    {
        currentPlayer = p2;
    }
    else
    {
        currentPlayer = p1;
    }
}



//Joue un coup dans la partie
/*La fonction pose le pion du coup joué sur la plateau. Si le coup est invalide, la fonction retourne 'false', sinon
le pion est posé, le plateau et les scores sont mis à jour et la fonction retourne 'true'.
*/
bool GameEngine::playMove(Move m)
{
    bool ret;   //value returned

    //Récupération et MAJ de la couleur du coup à joué
    m.setColor( playerTable[currentPlayer]->getColor() );
    //Ajout du pion sur l'othellier
    ret = board->addPawn( m.getX(), m.getY(), m.getColor() );

    if( ret )  //Si coup légal alors...
    {
		redoAllowed = false;
//		enableRedoMoveAction(false);
    	initializationSavingMove();  //Initialisation de la liste des coups sauvés
//    	saveRegularMoves();  //Sauvegarde les coups réguliers
//    	saveCurrentPlayer();  //Sauvegarde du joueur courrant

        playerTable[currentPlayer]->increaseScore();  //1 pt en plus pr le pion posé
        addMoveList(m);  //ajout du coup ds la liste
        updateGame(m);  //MAJ des données du jeu
        updatingScoreDisplay();  //MAJ de l'affichage des scores

        nextPlayer();  //joueur suivant

        definingRegularMoves();  //Définition des nouveaux 'coups légaux'
		updatingNumMovesDisplay();  //MAJ de l'affichage des 'coups légaux'
		
        if( playerTable[currentPlayer]->getNumMoves() == 0 ) //Si le joueur ne peut pas joué
        {
            nextPlayer();
            if( playerTable[currentPlayer]->getNumMoves() == 0 ) //Aucun joueurs ne peut jouer
            {
                isFinished = true;
            }
        }

        if( !isFinished )
        {
            updateRegularMove();    //MAJ des coups légaux du joueur courant sur l'othellier
			saveCurrentPlayer();
			saveRegularMoves();  //Sauvegarde les coups réguliers		
			//MAJ de 'numCurrentMove'
			numCurrentMove ++;
        }
		
//		affichageMovesList();
//		affichageSavedList();
		
//		board->hasModified();
		boardHasModified();
				
		undoAllowed = true;
//		enableUndoMoveActionGlobal(true);
//		emit enableUndoMoveAction(true);
    }
    else  //Coup illégal...
    {
    	askMove();
		//Affichage : "Coup illégal... Recommencez.
    }
    return ret;
}



//Définition des "coups légaux"
void GameEngine::definingRegularMoves()
/*Parcours le plateau de jeu et compte le nb de coups légaux pr chaques joueurs*/
{
    ColorPawn colorTmp;
    bool WhiteRegularMove = false,  //permet de ne pas compter un coup légal plusieurs fois pr un joueur...
         BlackRegularMove = false;

    //RAZ des coups légaux de chaques joueurs
    playerTable[p1]->RazNumMoves();
    playerTable[p2]->RazNumMoves();
    //RAZ de la liste de coups légaux
    regularMovesListTemp.clear();


    /************ Calcul des coups légaux du plateau ********/
    for( int y=0 ; y<8 ; y++ )
    {
        for( int x=0 ; x<8 ; x++ )
        {

/*********** Parcours chaque cases du plateau ********************/

            //Si la case est vide = Coup légal potentiel
            if( board->getTypeSquareBoard(x,y)==Empty )
            {

                //RAZ des indicateurs de coup légaux pr la case
                BlackRegularMove = false;
                WhiteRegularMove = false;


/*********** Parcours des cases voisines *********************/
                for( int j=-1 ; j<2 ; j++ )
                {

                    if( (y+j)>=0 && (y+j)<8 )  //si on est ds le tableau
                    {
                        for( int i=-1 ; i<2 ; i++ )
                        {
                            if( (x+i)>=0 && (x+i)<8 )  //si on est ds le tableau
                            {

                                if( !(i==0 && j==0) )  //On ne check pas la case elle-même
                                {

                                    //Vérifie si la case est un coup légal pour la ligne de vecteur (i,j)
                                    if( checkRegularMove(x, y, i, j) )
                                    {
                                        //Récupération de la couleur des pions encadrés
                                        colorTmp = board->getColorPawnBoard(x+i,y+j);
                                        //Si les pions encadrés st blans ET que les noirs n'ont encore pas de coup légal sur cette case
                                        if( colorTmp == White && !BlackRegularMove )
                                        {
                                            //Coup légal NOIR
                                            BlackRegularMove = true;
                                            increaseRegularMove(Black);
                                            //Ajout du coup légal ds la liste temporaire
                                            regularMovesListTemp.push_back( Move(x,y,Black) );
                                        }
                                        //Si les pions encadrés st blacks ET que les blans n ont encore pas de coup légal sur cette case
                                        else if( colorTmp == Black && !WhiteRegularMove )
                                        {
                                            //Coup légal BLANC
                                            WhiteRegularMove = true;
                                            increaseRegularMove(White);
                                            //Ajout du coup légal ds la liste temporaire
                                            regularMovesListTemp.push_back( Move(x,y,White) );
                                        }

                                        //Vérifie si les 2 couleurs ont un coup légal sur cette case
                                        //Auquel cas c est terminé pour cette case
                                        if( BlackRegularMove && WhiteRegularMove )
                                        {
                                            i=2;  j=2;  //Interruption des boucles for...
                                        }
                                    }
                                }

                            }
                        }
                    }

                }  //Fin parcours des cases voisines

            }
        }
    }  //Fin parcours du plateau
}



//MAJ des coups légaux contenu ds 'regularMovesList' sur l'othellier
void GameEngine::updateRegularMove()
{
    for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
    {
        if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
        {
            board->addRegularMove( regularMovesListTemp[i].getX(), regularMovesListTemp[i].getY() );
        }
    }
}



//Incrémentation d'un coup légal
//La fonction incrémente le nb de coups légaux du joueur dont la couleur est 'color'
void GameEngine::increaseRegularMove(ColorPawn color)
{
    if( playerTable[p1]->getColor() == color )
    {
        playerTable[p1]->increaseRegularMove();
    }
    else
    {
        playerTable[p2]->increaseRegularMove();
    }
}



/*Vérification d'un coup légal suivant plusieurs paramètres...
  Vérifie si les cases du plateau (à partir de la case [squareX,squareY]) selon la ligne de vecteur
  (i,j) représente une configuration pour un coup légal.*/
bool GameEngine::checkRegularMove(int squareX, int squareY, int i, int j)
{
    bool ret = false,  //value returned
         done = false; //end of boucle
    int x = squareX + i,
        y = squareY + j;

    //Vérifie si la case suivante est occupée
    if( board->getTypeSquareBoard(x,y)==Occupied )
    {
        ColorPawn colorTmp = board->getColorPawnBoard(x,y);
        x += i;
        y += j;
        while( x>=0 && x<8 && y>=0 && y<8 && !done)
        {
            if( board->getTypeSquareBoard(x,y)==Occupied )  //Si case occupée
            {
                if( board->getColorPawnBoard(x,y)==colorTmp )
                {
                    x += i;
                    y += j;
                }
                else  //Pion de l autre couleur, dc coup légal
                {
                    ret = true;
                    done = true;
                }
            }
            else  //Case vide dc pas de coup légal
            {
                done = true;
            }
        }
    }
    return ret;
}



//Retourne un pion
void GameEngine::turnDownPawn(int x, int y)
{
	board->turnDownPawn(x,y);
	savePawnTurnedDown(x,y);
}



/* Ajout du coup 'm' à la liste des coups joués
**
** Récupération du numéro du coup joué.
** Ajout du coup à la fin du vector 'movesList'
*/
void GameEngine::addMoveList(Move m)
{
/*    //Si vecteur vide, le numéro du coup est 0
    if( movesList.empty() )
    {
        m.setNumMove(1);
    }
    //Sinon récupération du num du dernier coup et incrémentation de 1
    else
    {
        m.setNumMove( movesList.back().getNumMove()+1 );
    }

    movesList.push_back(m);
    updatingMovesListDisplay();
*/
	
	//Si numCurrentMove ne correspond pas au dernier coup joué, on supprime les coups
	if( numCurrentMove != movesList.size() )
	{
		movesList.erase( movesList.begin()+numCurrentMove, movesList.end() );
	}
	//MAJ du numéro du coup joué
	m.setNumMove( numCurrentMove + 1 );
	//Ajoute le coup à la fin de la liste
	movesList.push_back(m);
	//MAJ de l'affichage
	updatingMovesListDisplay();
}



//Efface la liste de moves joués
void GameEngine::clearMovesList()
{
	movesList.clear();
	updatingMovesListDisplay();
}



/* Mise à jour des scores (appelée lorsqu'un pion du joueur actif est retourné)
**
** La fonction ajoute un point au joueur courant et soustrait un point à son
** adversaire.
*/
void GameEngine::updateScore()
{
    if( currentPlayer == p1 )
    {
        playerTable[p1]->increaseScore();
        playerTable[p2]->decreaseScore();
    }
    else
    {
        playerTable[p1]->decreaseScore();
        playerTable[p2]->increaseScore();
    }
}



/* Mise à jour des pions et des scores de la partie après avoir joué le coup 'm'
**
**
*/
bool GameEngine::updateGame(Move m)
{
    updateRow(m);
    updateColumn(m);
    updateDiagonal(m);
}



//MAJ des pions de la ligne du coup joué
void GameEngine::updateRow(Move m)
{
    //Récupération coord du coup
    int xMove = m.getX(),
        yMove = m.getY();
    //Récupération de la couleur
    ColorPawn colorMove = m.getColor();

    int i; //indice de parcours


/*--------------- Vérification à la GAUCHE du coup 'm' ---------------------*/
    i = xMove-1;
    /*On se décale à gauche tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)!=colorMove )
    {
        i--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++;//On se recale sur la première case adverse (la première à la droite...)
            while( i<xMove )
            {
//                board->turnDownPawn(i,yMove);  //Retournement du pion
				turnDownPawn(i,yMove);  //retournement du pion
                this->updateScore();  //On adapte les scores
                i++;  //On passe à la case suivante à droite
            }
        }
    }

/*--------------- Vérification à la DROITE du coup 'm' ---------------------*/
    i = xMove+1;
    /*On se décale à droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)!=colorMove )
    {
        i++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--;//On se recale sur la première case adverse (la première à la gauche...)
            while( i>xMove )
            {
//                board->turnDownPawn(i,yMove);  //Retournement du pion
				turnDownPawn(i,yMove);
                this->updateScore();  //On adapte les scores
                i--;  //On passe à la case suivante à gauche
            }
        }
    }
}


//MAJ des pions de la colonne du coup joué
void GameEngine::updateColumn(Move m)
{
    //Récupération coord du coup
    int xMove = m.getX(),
        yMove = m.getY();
    //Récupération de la couleur
    ColorPawn colorMove = m.getColor();

    int i; //indice de parcours


/*--------------- Vérification au DESSUS du coup 'm' ---------------------*/
    i = yMove-1;
    /*On se décale en haut tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)!=colorMove )
    {
        i--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++;//On se recale sur la première case adverse (la première en dessous...)
            while( i<yMove )
            {
//                board->turnDownPawn(xMove,i);  //Retournement du pion
				turnDownPawn(xMove,i);
                this->updateScore();  //On adapte les scores
                i++;  //On passe à la case suivante en dessous
            }
        }
    }

/*--------------- Vérification en DESSOUS du coup 'm' ---------------------*/
    i = yMove+1;
    /*On se décale à droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)!=colorMove )
    {
        i++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--;//On se recale sur la première case adverse (la première au dessus...)
            while( i>yMove )
            {
//                board->turnDownPawn(xMove, i);  //Retournement du pion
                turnDownPawn(xMove,i);
                this->updateScore();  //On adapte les scores
                i--;  //On passe à la case suivante à gauche
            }
        }
    }
}


//MAJ des pions des diagonales du coup joué
void GameEngine::updateDiagonal(Move m)
{
    //Récupération coord du coup
    int xMove = m.getX(),
        yMove = m.getY();
    //Récupération de la couleur
    ColorPawn colorMove = m.getColor();

    int i,j; //indices de parcours


/*--------------- Vérification diagonale HAUT-GAUCHE du coup 'm' ---------------------*/
    i = xMove-1;
    j = yMove-1;
    /*On se décale en haut-gauche tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && j>=0 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i--;
        j--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 && j>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++; j++;//On se recale sur la première case adverse (la première en bas-droite...)
            while( i<xMove && j<yMove )
            {
//                board->turnDownPawn(i,j);  //Retournement du pion
  				turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i++; j++; //On passe à la case suivante en bas-droite
            }
        }
    }

/*--------------- Vérification en BAS-DROITE du coup 'm' ---------------------*/
    i = xMove+1;
    j = yMove+1;

    /*On se décale en bas-droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && j<8 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i++;
        j++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 && j<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--;  j--;//On se recale sur la première case adverse (la première en haut-gauche...)
            while( i>xMove && j>yMove )
            {
//                board->turnDownPawn(i, j);  //Retournement du pion
                turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i--;  j--;//On passe à la case suivante en haut-gauche
            }
        }
    }

/*--------------- Vérification diagonale HAUT-DROITE du coup 'm' ---------------------*/
    i = xMove+1;
    j = yMove-1;
    /*On se décale en haut-droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && j>=0 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i++;
        j--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 && j>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--; j++;//On se recale sur la première case adverse (la première en bas-gauche...)
            while( i>xMove && j<yMove )
            {
//                board->turnDownPawn(i,j);  //Retournement du pion
                turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i--; j++; //On passe à la case suivante en bas-gauche
            }
        }
    }

/*--------------- Vérification en BAS-GAUCHE du coup 'm' ---------------------*/
    i = xMove-1;
    j = yMove+1;

    /*On se décale en bas-gauche tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && j<8 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i--;
        j++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 && j<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++;  j--;//On se recale sur la première case adverse (la première en haut-droite...)
            while( i<xMove && j>yMove )
            {
//                board->turnDownPawn(i, j);  //Retournement du pion
                turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i++;  j--;//On passe à la case suivante en haut-droite
            }
        }
    }
}



void GameEngine::askMove()
{
/*	QString str = playerTable[currentPlayer]->getName() + " ( ";
	if( playerTable[currentPlayer]->getColor() == Black )
	{
		str += "black";
	}
	else
	{
		str += "white";
	}
	str += " pawns ) is playing ...";
	emit sendInfosGameDisplay(str);
*/
	//Envoie msg joueur courrant
	if( currentPlayer == p1 )
	{
		emit sendInfosGameDisplay(P1_Playing);
	}
	else
	{
		emit sendInfosGameDisplay(P2_Playing);
	}
	
	switch( playerTable[currentPlayer]->getType() )
	{
		case Local:  //Si le joueur courant est un utilisateur local
			emit enableRedoMoveAction(redoAllowed);
			emit enableUndoMoveAction(undoAllowed);
			emit askingLocalMove();
			break;
		case AI_1:
		case AI_2:
		case AI_3:
			emit askingAIMove(this);
			break;
		default:
			break;
	}
}



void GameEngine::whoWins()
{
    if( playerTable[p1]->getScore() > playerTable[p2]->getScore() )
    {
		emit playerWins( playerTable[p1] );
    }
    else if( playerTable[p1]->getScore() < playerTable[p2]->getScore() )
    {
		emit playerWins( playerTable[p2] );
    }
    else
    {
		emit playerWins( NULL );
    }

}



void GameEngine::updatingScoreDisplay()
{
	emit playerScoreModified();
//	emit playerScoreModified(playerTable[p1]);
//	emit playerScoreModified(playerTable[p2]);
}



void GameEngine::updatingNumMovesDisplay()
{
	emit playerNumMovesModified();
//	emit playerNumMovesModified(playerTable[p1]);
//	emit playerNumMovesModified(playerTable[p2]);
}



void GameEngine::updatingMovesListDisplay()
{
	//créer la chaine à afficher
	QString str = "";
//	if( numCurrentMove == 0 )
	if( movesList.empty() )
    {
        str = "No Moves played";
    }
    //Sinon récupération du num du dernier coup et incrémentation de 1
    else
    {
   		QString str_temp;
    	vector<Move>::iterator iv = movesList.begin();
    	int coord;    	
//--- Bidouille pour afficher ou pas le coup n° 'numCurrentMove'
//--- On ne l'affiche pas ( borne-- ) s'il a été annulé avec undoMove (dc si redoAllowed == true )...
		int borne = numCurrentMove+1;
		if( redoAllowed )
		{
			borne--;
		}
		//Pour ne pas dépasser du vector en mémoire...
		if( borne > movesList.size() )
		{
			borne = movesList.size();
		}
//-----------------------------------------------------------------//
    	while( iv != (movesList.begin()+/*numCurrentMove+1*/borne) )
    	{
    		str_temp.setNum( iv->getNumMove() );
    		str += str_temp;
    		str += ":  ";
    		coord = iv->getX();
    		str += 'A' + coord;
    		str_temp.setNum( iv->getY() + 1 );
    		str += str_temp;
    		str += "  ";
    		if( iv->getColor() == Black )
    		{
    			str += "Black";
    		}
    		else
    		{
    			str += "White";
    		}
    		str += "\n";
    		iv++;
    	}

/*		int borne = numCurrentMove+1;
		if( redoAllowed )
		{
			borne--;
		}
		if( borne > movesList.size() )
		{
			borne = movesList.size();
		}
		QString str_temp;
		int coord;
	cout << "borne = " << borne << "  et  movesList.size()= " << movesList.size() << endl;
		for( int i=0 ; i<borne ; i++ )
		{
    		str_temp.setNum( movesList[i].getNumMove() );
    		str += str_temp;
    		str += ":  ";
    		coord = movesList[i].getX();
    		str += 'A' + coord;
    		str_temp.setNum( movesList[i].getY() + 1 );
    		str += str_temp;
    		str += "  ";
    		if( movesList[i].getColor() == Black )
    		{
    			str += "Black";
    		}
    		else
    		{
    			str += "White";
    		}
    		str += "\n";
		}
*/	
	}
    emit movesListModified(str);
}



void GameEngine::playerInitializationDisplay()
{
	emit playerColorModified(playerTable[p1]);
	emit playerColorModified(playerTable[p2]);

	emit playerNameModified(playerTable[p1]);
	emit playerNameModified(playerTable[p2]);

	emit playerTypeModified(playerTable[p1]);
	emit playerTypeModified(playerTable[p2]);

//Pas d'affichage du score et num moves au démarage du jeu...C est un choix!!
//	updatingScoreDisplay();
//	updatingNumMovesDisplay();	
}



void GameEngine::boardHasModified()
{
	emit boardModified();
}



//Initialisation de la sauvegarde du coup courrant
void GameEngine::initializationSavingMove()
{
	if( movesSavedList.size() != numCurrentMove )  //Si le vector contient plus de coup que le numéro du coup courrant
	{
		//Suppression des coups supplémentaires
		movesSavedList.erase(movesSavedList.begin()+numCurrentMove, movesSavedList.end() );
	}
	//Ajout d'un InfosMoves à la fin
	movesSavedList.push_back( InfosMoves() );
}



//Ajoute un pion retourné ds la liste des pions retournés du coup courrant
void GameEngine::savePawnTurnedDown(int x, int y)
{
	movesSavedList[numCurrentMove].addPawnsTurnedDown( Move(x,y) );
}



//Sauvegarde la liste des coups réguliers du coup courrant
void GameEngine::saveRegularMoves()
{
	movesSavedList[numCurrentMove].saveRegularMoves(regularMovesListTemp);
}



//Save current player
void GameEngine::saveCurrentPlayer()
{
	movesSavedList[numCurrentMove].saveCurrentPlayer(currentPlayer);
}

void GameEngine::affichageSavedList()
{
	cout << "#---- Saved List:" << endl;
	for( int i=0 ; i<movesSavedList.size() ; i++ )
	{
		cout << "\t" << i << ":" << endl;
		movesSavedList[i].affichage();
	}
}


void GameEngine::undoLastMove()
{
	if( numCurrentMove > 0 )
	{
		Move moveTmp;
	//On se recale sur le coup précédent
		numCurrentMove--;
	//Récupérer le joueur courant
		if( numCurrentMove == 0 ) //Config de départ
		{
			//Le joueur qui a commencé est le joueur qui a les pions noirs
			if( playerTable[p1]->getColor() == Black )
			{
				currentPlayer = p1;
			}
			else
			{
				currentPlayer = p2;
			}
		}
		else
		{
			currentPlayer = movesSavedList[numCurrentMove-1].getCurrentPlayer();
		}
//-->envoie msg 'joueur courant' à l'interface
	//Retirer le dernier pion posé		
		board->emptySquare(movesList[numCurrentMove].getX(),movesList[numCurrentMove].getY());
		playerTable[currentPlayer]->decreaseScore();  //MAJ des scores
	//MAJ dernier coup sur le plateau si il existe
		if(numCurrentMove > 0)
		{
			board->enableLastMoveSquare(movesList[numCurrentMove-1].getX(),movesList[numCurrentMove-1].getY());
		}
	//Retourner les pions retournés
		for( int i=0 ; i<movesSavedList[numCurrentMove].getSizePawnsTurnedDownList() ; i++ )
		{
			moveTmp = movesSavedList[numCurrentMove].getPawnsTurnedDownList(i);
			board->turnDownPawn(moveTmp.getX(),moveTmp.getY());
			//MAJ des scores
			if( currentPlayer == p1 )
			{
				playerTable[p1]->decreaseScore();
				playerTable[p2]->increaseScore();
			}
			else
			{
				playerTable[p1]->increaseScore();
				playerTable[p2]->decreaseScore();
			}
		}
		board->clearAnimation();  //Pas d'animation
	//MAJ des coups légaux
		board->clearRegularMove();
		regularMovesListTemp.clear();
		int numMovesCurPlayer = 0;
//		cout << "!!!! getSizeRegularMoveList()= " << movesSavedList[numCurrentMove].getSizeRegularMovesList() << endl;
//		int CPT = 0;
/*		for( int i=0 ; i<movesSavedList[numCurrentMove].getSizeRegularMovesList() ; i++ )
		{
//			CPT++;
			moveTmp = movesSavedList[numCurrentMove].getRegularMovesList(i);  //
			regularMovesListTemp.push_back(moveTmp);
			if( moveTmp.getColor() == playerTable[currentPlayer]->getColor() )
			{
				board->addRegularMove( moveTmp.getX(),moveTmp.getY() );
				numMovesCurPlayer++;
			}
		}
*/		//Récupération des coups réguliers ds 'regularMovesListTemp'
		if( numCurrentMove == 0 ) //Configuration de départ
		{
			regularMovesListTemp.push_back( Move(2,3,Black) );
			regularMovesListTemp.push_back( Move(3,2,Black) );
			regularMovesListTemp.push_back( Move(4,5,Black) );
			regularMovesListTemp.push_back( Move(5,4,Black) );
			regularMovesListTemp.push_back( Move(5,3,White) );
			regularMovesListTemp.push_back( Move(4,2,White) );
			regularMovesListTemp.push_back( Move(2,4,White) );
			regularMovesListTemp.push_back( Move(3,5,White) );
		}
		else
		{
			regularMovesListTemp = movesSavedList[numCurrentMove-1].getRegularMovesList();
		}
		//MAJ coups réguliers sur le plateau
		for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
		{
			if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
			{
				board->addRegularMove( regularMovesListTemp[i].getX(), regularMovesListTemp[i].getY() );
				numMovesCurPlayer++;
			}
		}
		
//		cout << "!!!!! CPT= " << CPT << endl;
		if( currentPlayer == p1 )
		{
			playerTable[p1]->setNumMoves(numMovesCurPlayer);
			playerTable[p2]->setNumMoves(regularMovesListTemp.size()-numMovesCurPlayer);
		}
		else
		{
			playerTable[p1]->setNumMoves(regularMovesListTemp.size()-numMovesCurPlayer);
			playerTable[p2]->setNumMoves(numMovesCurPlayer);
		}
	//MAJ affichage
/*		updatingScoreDisplay();
		updatingNumMovesDisplay();
		updatingMovesListDisplay();
		boardHasModified();
*/	//MAJ affichage 'undoAction' and 'redoAction'
		redoAllowed = true;
//		emit enableRedoMoveAction(true);
		if( numCurrentMove == 0 )
		{
			undoAllowed = false;
//			emit enableUndoMoveAction(false);
		}
	}
}


void GameEngine::redoLastMove()
{
	if( numCurrentMove < (movesList.size()) )  //Si il y a un coup a rejouer
	{
		Move moveTmp;
	//Ajouter le dernier pion posé
		board->addPawn(movesList[numCurrentMove].getX(), movesList[numCurrentMove].getY(),playerTable[currentPlayer]->getColor() );
		playerTable[currentPlayer]->increaseScore();  //MAJ des scores
	//Retourner les pions retournés
		for( int i=0 ; i<movesSavedList[numCurrentMove].getSizePawnsTurnedDownList() ; i++ )
		{
			moveTmp = movesSavedList[numCurrentMove].getPawnsTurnedDownList(i);
			board->turnDownPawn(moveTmp.getX(),moveTmp.getY());
			//MAJ des scores
			if( currentPlayer == p1 )
			{
				playerTable[p1]->increaseScore();
				playerTable[p2]->decreaseScore();
			}
			else
			{
				playerTable[p1]->decreaseScore();
				playerTable[p2]->increaseScore();
			}
		}
		board->clearAnimation();  //Pas d'animation
	//Récupérer le joueur courant
		currentPlayer = movesSavedList[numCurrentMove].getCurrentPlayer();	
	//MAJ des coups légaux
		board->clearRegularMove();
		regularMovesListTemp.clear();
		//Recopie des coups réguliers ds 'regularMovesListTemp'
		regularMovesListTemp = movesSavedList[numCurrentMove].getRegularMovesList();
		int numMovesCurPlayer = 0;
//		cout << "!!!! getSizeRegularMoveList()= " << movesSavedList[numCurrentMove].getSizeRegularMovesList() << endl;
//		int CPT = 0;
		//On affiche les coups réguliers sur le board
		for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
		{
//			CPT++;
			if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
			{
				board->addRegularMove( regularMovesListTemp[i].getX(), regularMovesListTemp[i].getY() );
				numMovesCurPlayer++;
			}
		}
//		cout << "!!!!! CPT= " << CPT << endl;
		//MAJ 'numMoves' des joueurs
		if( currentPlayer == p1 )
		{
			playerTable[p1]->setNumMoves(numMovesCurPlayer);
			playerTable[p2]->setNumMoves(regularMovesListTemp.size()-numMovesCurPlayer);
		}
		else
		{
			playerTable[p1]->setNumMoves(regularMovesListTemp.size()-numMovesCurPlayer);
			playerTable[p2]->setNumMoves(numMovesCurPlayer);
		}
	//On passe au coup suivant
		numCurrentMove++;
	//MAJ affichage
/*		updatingScoreDisplay();
		updatingNumMovesDisplay();
		updatingMovesListDisplay();
		boardHasModified();
*/	//MAJ affichage 'undoAction' and 'redoAction'
		undoAllowed = true;
//		emit enableUndoMoveAction(true);
		if( numCurrentMove == (movesList.size()) )
		{
			redoAllowed = false;
//			emit enableRedoMoveAction(false);
		}	
	}
}

void GameEngine::affichageMovesList()
{
	for( int i=0 ; i<movesList.size() ; i++ )
	{
		cout << "Move " << i << " : ";
		movesList[i].affichage();
	}
}

void GameEngine::undoMoveGlobal()
{
	//Détecter le cas & Annulation des coups en conséquence
	int idTmp = p1;
	if( currentPlayer == p1 ) //Récupère l id du joueur non courant
	{
		idTmp = p2;
	}
	switch( playerTable[idTmp]->getType() )
	{
		case AI_1:
		case AI_2:
		case AI_3:
			//Si le joueur adverse est une IA, on doit annuler les coups de telle sorte que
			// le joueur courant annule son dernier coup joué
			do
			{
				undoLastMove();
			}
			while( currentPlayer == idTmp && numCurrentMove != 0 ); //Tant que le joueur courant est l'IA ou ke l on revienne au premier coup
			break;
		case Local:
			undoLastMove();
			break;
		default:
			break;
	}
	//MAJ affichage	
	updatingScoreDisplay();
	updatingNumMovesDisplay();
	updatingMovesListDisplay();
	boardHasModified();
	//Relancer le moteur de jeu en demandant un coup au moteur adéquate
	askMove();
}

void GameEngine::redoMoveGlobal()
{
	//Détecter le cas & Annulation des coups en conséquence
	int idTmp = p1;
	if( currentPlayer == p1 ) //Récupère l id du joueur non courant
	{
		idTmp = p2;
	}
	switch( playerTable[idTmp]->getType() )
	{
		case AI_1:
		case AI_2:
		case AI_3:
			//Si le joueur adverse est une IA, on doit annuler les coups de telle sorte que
			// le joueur courant annule son dernier coup joué
			do
			{
				redoLastMove();
			}
			while( currentPlayer == idTmp && numCurrentMove != movesList.size() ); //Tant que le joueur courant est l'IA ou ke l on revienne au premier coup
			break;
		case Local:
			redoLastMove();
			break;
		default:
			break;
	}
	//MAJ affichage	
	updatingScoreDisplay();
	updatingNumMovesDisplay();
	updatingMovesListDisplay();
	boardHasModified();
	//Relancer le moteur de jeu en demandant un coup au moteur adéquate
	askMove();

}


vector<InfosMoves> GameEngine::getMovesSavedList()
{
	return movesSavedList;
}

int GameEngine::getNumCurrentMove()
{
	return numCurrentMove;
}
